<?php
error_reporting(E_ERROR);

/**
 * 单询多个数据
 * @version 1.0.0 首次引入
 * @param string $ptah 模型路径
 * @param string $args 查询参数
 * @return array
 */
function dcSelect($path='',$args=[]){
    return model($path,'loglic')->select($args);
}

/**
 * 按分页单询多个数据
 * @version 1.0.0 首次引入
 * @param string $ptah 模型路径
 * @param string $args 查询参数
 * @return array
 */
function dcSelectPage($path='',$args=[], $pageSize=10, $pageNumber=1, $isTotal=false, $query=['page'=>1]){
    return model($path,'loglic')->selectPage($args, $pageSize, $pageNumber, $isTotal, $query);
}

/**
 * 匹配数字
 * @version 1.0.0 首次引入
 * @param string $string 文本
 * @return int
 */
function dcNumber($string='')
{
    return dcPregMatch('([0-9]+)',$string);
}

/**
 * 数组保存到文件
 * @version 1.0.0 首次引入
 * @param string $filename 完整文件路径名
 * @param string $dataArray 数组
 * @return bool
 */
function dcWriteArray($fileName='', $dataArray=''){
    $file = model('common/File','loglic');
    if(!$file->f_has($fileName)){
        return 0;
    }
    if(!$file->is_write($fileName)){
        return 0;
    }
    return $file->write_array($fileName, $dataArray);
}

/**
 * 读取远程数据
 * @version 1.0.0 首次引入
 * @param string $useragent 必需;模拟用户HEAD头,可选值有（auto|windows|linux|ios|iphone）;默认：auto
 * @param int $timeout 必需;超时时间;默认：10
 * @param string $url 必需;待抓取的远程地址;默认：空
 * @param array $post_data 可选;post请求时发送的数据，留空则为get请求;默认：空
 * @param string $referer 可选;模拟来湃URL地址;默认：空
 * @param array $headers 可选;自定义请求头;默认：空
 * @param string $cookie 可选;模拟cookie信息;默认：空
 * @param string $proxy 可选;代理请求信息;默认：空
 * @return string 返回读取远程网页的内容
 */
function dcCurl($useragent='auto', $timeout=10, $url='', $post_data='', $referer='', $headers=[], $cookie='', $proxy=''){
    $ch = curl_init();
    curl_setopt ($ch, CURLOPT_URL, $url);
    curl_setopt ($ch, CURLOPT_HEADER, 0);
    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1); 
    curl_setopt ($ch, CURLOPT_TIMEOUT, $timeout);
    curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
    curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1);//301 302
    curl_setopt ($ch, CURLOPT_ENCODING, "");//乱码是因为返回的数据被压缩过了，在curl中加上一项参数即可
    //useragent
    if($useragent == 'windows'){
        curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows;U;WindowsNT6.1;en-us)AppleWebKit/534.50(KHTML,likeGecko)Version/5.1Safari/534.50');
    }elseif($useragent == 'linux'){
        curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:20.0) Gecko/20100101 Firefox/20.0');
    }elseif($useragent == 'ios'){
        curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh;U;IntelMacOSX10_6_8;en-us)AppleWebKit/534.50(KHTML,likeGecko)Version/5.1Safari/534.50');
    }elseif($useragent == 'iphone'){
        curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X; zh-CN) AppleWebKit/537.51.1 (KHTML, like Gecko) Mobile/14F89 UCBrowser/10.9.17.807 Mobile');
    }elseif($useragent == 'android'){
        curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Linux; U; Android 7.1.1; zh-cn; OPPO R11st Build/NMF26X) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.134 Mobile Safari/537.36 OppoBrowser/4.6.5.3');
    }    
    //是否post
    if(is_array($post_data)){
        curl_setopt($ch, CURLOPT_POST, 1);// post数据
        if($headers[0] == 'Content-Type: application/json'){
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));    // post的变量
        }else{
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);    // post的变量
        }
    }
    //是否伪造来路
    if($referer){
        curl_setopt ($ch, CURLOPT_REFERER, $referer);
    }
    //是否headers
    if(is_array($headers)){
        curl_setopt ($ch, CURLOPT_HTTPHEADER, $headers);
    }    
    //是否cookie
    if($cookie){
        curl_setopt ($ch, CURLOPT_COOKIE, $cookie);
    }
    //IP代理
    if($proxy){
        curl_setopt ($ch, CURLOPT_PROXY, $proxy);
    }    
    //https自动处理
    $http = parse_url($url);
    if($http['scheme'] == 'https'){
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    }
    $content = curl_exec($ch);
    curl_close($ch);
    //返回结果
    if($content){
        return $content;
    }
    return false;
}

function dcPregMatch($rule='', $html=''){
    $arr = explode('$$$',$rule);
    if(count($arr) == 2){
        preg_match('/'.$arr[1].'/', $html, $data);
        return $data[$arr[0]].'';
    }else{
        preg_match('/'.$rule.'/', $html, $data);
        return $data[1].'';
    }
}

function dcMarkdownParse($str){
    $parser = model('common/Markdown','loglic');
    $parser->_html = true;
    return $parser->makeHtml($str);
}

function dcFormCreate($args=[]){
    //表单字段属性
    foreach($args['items'] as $field=>$attr){
        if($attr['type']){
            $args['items'][$field] = dcFormItem($field, $attr);
        }else{
            unset($args['items'][$field]);
        }
    }
    //初始值
    $form = array();
    $form['name']           = '';//表单名称用于钩子判断
    $form['action']         = '#';//表单提交地址
    $form['method']         = 'post';//表单提交方法
    $form['target']         = '_self';//窗口打开方式
    $form['class']          = 'bg-white';//表单样式表
    $form['disabled']       = false;//是否禁用
    $form['ajax']           = true;//AJAX操作
    $form['call_back']      = '';//AJAX回调
    $form['submit']         = '提交';//提交按钮名称
    $form['reset']          = '';//重置按钮名称
    $form['close']          = '';//关闭按钮名称
    $form['class_row']      = 'w-100';//堆叠表单w-100,内联表单row
    $form['class_button']   = 'text-center';//按钮组
    $form['class_submit']   = 'btn btn-dark';//提交按钮CLASS
    $form['class_reset']    = 'btn btn-secondary';//重置按钮CLASS
    $form['class_close']    = 'btn btn-danger';//关闭按钮CLASS
    $form['items']          = [];//表单元素列表
    //参数合并
    $form = array_merge($form, $args);
    //释放内存
    unset($args);
    //模板渲染
    return view('./widget/form/index.tpl',$form)->getContent();
}

function dcFormItems($fields=[]){
    foreach($fields as $field=>$attr){
        if($attr['type']){
            $fields[$field] = dcFormItem($field, $attr);
        }else{
            unset($fields[$field]);
        }
    }
    return $fields;
}

function dcFormItem($field='', $attr=[], $isParse=false){
    //默认属性
    $default = [
        'type'                => 'text',
        'name'                => $field,
        'id'                  => $field,
        'value'               => '',
        'title'               => '',
        'placeholder'         => '',
        'tips'                => '',
        'autofocus'           => '',
        'readonly'            => false,
        'disabled'            => false,
        'required'            => false,
        'template'            => dcEmpty($attr['template'],'./widget/form/'.$attr['type'].'.tpl'),
        'class_row'           => 'w-100 mb-3',//row mb-3
        'class_label'         => 'form-label',//col-2 col-form-label
        'class_col'           => '',//col-10
        'class_input'         => 'form-control form-control-sm',
        'class_tips'          => '',
    ];
    //表单类型特有属性
    if( in_array($attr['type'],['text','url','email','number','password']) ){
        $default['maxlength']    = '200';
        $default['autocomplete'] = 'off';
    }elseif( in_array($attr['type'],['textarea','editor','json']) ){
        $default['rows']        = 10;
    }elseif( in_array($attr['type'],['custom','select']) ){
        $default['option']      = [];
        $default['class_input'] = 'form-select form-select-sm';
        if($attr['multiple']){
            $default['name']    = $field.'[]';
            $default['id']      = $field.'[]';
        }
    }elseif( in_array($attr['type'],['switch','radio']) ){
        $default['option']    = [];
        $default['class_row'] = 'form-check form-check-inline';
    }elseif( in_array($attr['type'],['checkbox']) ){
        $default['name']      = $field.'[]';
        $default['id']        = $field.'[]';
        $default['option']    = [];
        $default['class_row'] = 'form-check form-check-inline';
    }
    //返回结果
    return dcArrayArgs($attr, $default);
}

//渲染模板
function dcView($args=[]){
    $path = $args['template'] ? $args['template'] : './widget/form/default.tpl';
    return view($path,$args)->getContent();
}

/**
 * 给一个数组参数或者url字符串（args）绑定默认值
 * @version 1.0.0 首次引入
 * @param array $args 必需;数组参数列表
 * @param array $defaults 可选;数组默认值;默认：空
 * @return array 合并后的数组
 */
function dcArrayArgs($args=[], $defaults=''){
	if ( is_array( $args ) ){
		$r =& $args;
    }else{
		parse_str( $args, $r );
    }
	if ( is_array( $defaults ) ){
		return array_merge( $defaults, $r );
    }
	return $r;
}

/**
 * 过滤数组中不需要的字段
 * @version 1.0.0 首次引入
 * @param array $array 必需;待过滤的数组
 * @param array $fileds 必需;需保留的字段
 * @param string $prefix 可选;KEY前缀
 * @param string $suffix 可选;KEY后缀
 * @return mixed 过滤后的数组(array|value)
 */
function dcArrayFilter($array=[], $fileds=[], $prefix='', $suffix=''){
    $filter = [];
    foreach($array as $key=>$value){
        if(in_array($key, $fileds)){
            $filter[$prefix.$key.$suffix] = $value;
        }
    }
    return $filter;
}

/**
 * 判断是否为（普通/多维）数组
 * @version 1.0.0 首次引入
 * @param array $array 必需;待验证的数组;默认：空
 * @param bool $mode 可选;多维数组模式;默认：false
 * @return bool true|false
 */
function dcIsArray($array=[], $mode=false){
    //验证普通数组模式
    if($mode == false){
        return is_array($array);
    }
    //验证多维数组模式
    if(count($array, 1) == 1){
        return false;
    }
    //计算一维与多维是否相同，统计相同则是一维，不相同则是多维
    if (count($array) == count($array, 1)) {
        return false;
    } else {
        return true;
    }
}

/**
 * 将数据集转化为数组
 * @version 1.0.0 首次引入
 * @param mixed $data 必需;需验请的数据集;默认：空
 * @return mixed array|null
 */
function dcArrayResult($data=[]){
    if(is_null($data)){
        return null;
    }
    if(is_object($data)){
        return $data->toArray();
    }
    return $data;
}

/**
 * 返回数组的指定KEY
 * @version 1.0.0 首次引入
 * @param mixed $data 必需;需验请的数据集;默认：空
 * @return mixed array|null
 */
function dcArrayKey($array=[],$key='key'){
    return $array[$key];
}

/**
 * BOOL快捷输出
 * @version 1.0.0 首次引入
 * @param string $value 必需;待验证的字符串
 * @param bool $default 可选;验证规则;默认：true
 * @return string true|false
 */
function dcBool($value='', $default=true){
    $array = ['1', 'true', 'on', 'yes'];
    if(in_array(strtolower($value), $array)){
        return $default;
    }
    return false;
}

/**
 * OnOff快捷输出
 * @version 1.0.0 首次引入
 * @param string $value 必需;待验证的字符串
 * @return string on|off
 */
function dcSwitch($value=''){
    if( dcBool($value) ){
        return 'on';
    }
    return 'off';
}

/**
 * 隐藏完整手机号
 * @version 1.0.0 首次引入
 * @param string $mobile 必需;手机号
 * @return string 过滤后的手机号
 */
function dcMobile($mobile=''){
    return substr_replace($mobile, '****',3, 4);
}

/**
 * 字符串空值快捷输出
 * @version 1.0.0 首次引入
 * @param string $value 必需;待验证的字符串
 * @param mixed $default 必需;默认值;默认：空
 * @return string 验证后的字符串
 */
function dcEmpty($value='', $default=''){
    return !empty($value) ? $value : $default;
}

/**
 * 字符串作比较是否相同后输出不同值
 * @version 1.0.0 首次引入
 * @param string $value 必需;待验证的字符串
 * @param string $default 必需;待比较的字符串;默认：空
 * @param string $stringTrue 必需;比较结果为真时输出的字符;默认：active
 * @param string $empty 必需;比较结果为假时输出的字符;默认：空
 * @return string 验证后的字符串
 */
function dcDefault($value='', $default='', $stringTrue='active', $stringFalse=''){
    if(is_array($default)){
        if(in_array($value,$default)){
            return $stringTrue;
        }
    }else{
        if($value == $default){
            return $stringTrue;
        }
    }
    return $stringFalse;
}

/**
 * 字符串截取
 * @version 1.0.0 首次引入
 * @param string $str 必需;待截取的字符串
 * @param int $start 必需;起始位置;默认：0
 * @param int $length 必需;截取长度;默认：空
 * @param bool $suffix 可选;超出长度是否以...显示;默认：true
 * @param string $charset 可选;字符编码;默认：utf-8
 * @return string 截取后的字符串
 */
function dcSubstr($str='', $start=0, $length, $suffix=true, $charset="UTF-8"){
    $str = trim($str);
    if( function_exists('mb_strimwidth') ){
        if($suffix){
            return mb_strimwidth($str, $start, $length*2, '...', $charset);
        }
        return mb_strimwidth($str, $start, $length*2, '', $charset);
    }
    return @substr($str, $start, $length);
}

/**
* 下划线转驼峰
* @version 1.0.0 首次引入
* @param string $uncamelized_words 下划线样式的字符串
* @param string $separator 分隔符/默认'_'
* @return string 驼峰样式的字符串
* step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
* step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
*/
function dcCamelize($uncamelized_words='', $separator='_'){
    $uncamelized_words = $separator. str_replace($separator, " ", strtolower($uncamelized_words));
    return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator );
}

/**
 * 生成站内链接
 * @version 1.0.0 首次引入
 * @param string $url 必需;调用地址
 * @param string|array $vars 可选;调用参数，支持字符串和数组;默认：空
 * @return string 站内链接
 */
function dcUrl($url='', $vars=''){
    return str_replace('%5BPAGE%5D','[PAGE]',url($url, $vars, config('app.url_suffix'), false));
}

/**
 * 获取跳转URL
 * @version 1.0.0 首次引入
 * @return string 记忆的URL
 */
function dcUrlRedirect(){
    if($restore = input('session.redirect_url')){
        session('redirect_url', null);
        return $restore;
    }else{
        return 'user/index/index';
    }
}

/**
 * 对查询结果集进行排序
 * @version 1.0.0 首次引入
 * @param array $list 查询结果
 * @param string $field 排序的字段名
 * @param string $sortby 排序类型 (asc正向排序 desc逆向排序 nat自然排序)
 * @param bool $oldkey 是否保留原key
 * @return array
 */
function list_sort_by($list=[], $field='', $sortby='asc', $oldkey=false) {
   if(is_array($list)){
       $refer = $resultSet = array();
       foreach ($list as $i => $data)
           $refer[$i] = &$data[$field];
       switch ($sortby) {
           case 'asc': // 正向排序
                asort($refer);
                break;
           case 'desc':// 逆向排序
                arsort($refer);
                break;
           case 'nat': // 自然排序
                natcasesort($refer);
                break;
       }
       foreach ($refer as $key=> $val){
           if($oldkey){
               $resultSet[$key] = &$list[$key];
           }else{
               $resultSet[] = &$list[$key];
           }
       }
       return $resultSet;
   }
   return false;
}

/*** 
 * 把返回的数据转换成Tree
 * @version 1.0.0 首次引入
 * @param array $list 要转换的数据集
 * @param string $pid parent标记字段
 * @param string $level level标记字段
 * @return array 
 */
function list_to_tree($list=[], $pk='id', $pid = 'pid', $child = '_child', $root=0)
{
    // 创建Tree
    $tree = array();
    if(is_array($list)) {
        // 创建基于主键的数组引用
        $refer = array();
        foreach ($list as $key => $data) {
            $refer[$data[$pk]] =& $list[$key];
        }
        foreach ($list as $key => $data) {
            // 判断是否存在parent
            $parentId = $data[$pid];
            if ($root == $parentId) {
                $tree[] =& $list[$key];
            }else{
                if (isset($refer[$parentId])) {
                    $parent =& $refer[$parentId];
                    $parent[$child][] =& $list[$key];
                }
            }
        }
    }
    return $tree;
}

/**
 * 将树状还原成带层维数的数据列表/用于表格展示
 * @version 1.0.0 首次引入
 * @param  array $tree  原来的树
 * @param  string $pkName 要添加符号的键名
 * @param  string $level 记录无限层级关系 
 * @param  string $child 孩子节点的键
 * @param  array  $list  过渡用的中间数组，
 * @return array 返回排过序的列表数组
 */
function tree_to_level($tree=[], $pkName='', $level=0, $child='_child', &$list = array()){
    if(is_array($tree)) {
        $icon   = '';
        if ($level > 0) {
            $icon = '|';
            for ($i=0; $i < $level; $i++) {
                $icon .= '──';
            }
        }
        $refer = array();
        foreach ($tree as $value) {
            $reffer = $value;
            if($pkName){
                $reffer[$pkName] = $icon.$reffer[$pkName];
            }
            if(isset($reffer[$child])){
                unset($reffer[$child]);
                $list[] = $reffer;
                tree_to_level($value[$child], $pkName, $level+1, $child, $list);
            }else{
                $list[] = $reffer;
            }
        }
    }
    return $list;
}